/*
 * EXT2
 */
#include "../include/types.h"
#include "../include/const.h"
#include "../include/string.h"
#include "../include/mem.h"
#include "../include/ide.h" /*CC_PRIMARY, ReadSectorsLba */
#include "../include/idelow.h" /* SelectAtaChannel */
#include "../include/kernelheap.h"
#include "../include/monitor.h"
#include "../include/keyboard.h"
#include "../include/ext2.h"

#define min(a,b) (((a)<(b)) ? (a) : (b))

struct i_node_tab{
  u32int i_node_n;
  struct i_node inode;
  u16int ref;
} *inode_table;

struct date_ext2{
    u32int day;
    u32int month;
    u32int year;
}data;

struct time_ext2{
    u32int seconds;
    u32int min;
    u32int hour;
}tempo;

u16int dim_inode_table;
u16int free_inode;
struct super_block *super;
struct group_descriptor  *group_desc_table;
u8int *data_block;
int err;
boolean mount_ext2 = FALSE;

char path_ext2[1024];
int level;

u32int * ptr_dir;

u16int count_dir; /* Dabartine directorija */
char** ext2_file_name; /* Failo pavadinimas */
u32int * inode_dir; /* inodes */
u8int* file_type_dir; /* Failo tipas */
char* text;
char* name;

char path_ext2_backup[1024];
int level_backup;
u32int ino_dir_backup, ino_current_dir;

u16int spb, bpg, gdpb, ipb, sbpos;
u32int number_of_groups; 
u32int dim_block, dim_ptr, dim_frag; 
u32int inodes_per_block; 
u32int dir_entries_per_block; 

/* Blokas paverčiamas į Logical block addressing */
u32int block_to_LBA(s32int num_block){
  return(0 +(num_block*spb));
}

/*void stampa_bg(struct group_descriptor *bg){
  monitor_write(("\n\n\rid primo blocco bitmap blocchi: %u",bg->bg_block_bitmap);
  monitor_write(("\n\rid primo blocco bitmap inode: %u",bg->bg_inode_bitmap);
  monitor_write(("\n\rid primo blocco tabella inode: %u",bg->bg_inode_table);
  kgetchar(); 
}*/

boolean ReadGroupDescriptor(u32int grp, struct group_descriptor* data){
  if(grp>number_of_groups){
    return FALSE;
  }
  return TRUE;
}

/* Group descriptos table inicializacija */
boolean init_group_desc_table(){
  if(!(group_desc_table = (struct group_descriptor*)kmalloc(sizeof(struct group_descriptor)*number_of_groups))){
    monitor_write(("\n\rImpossible create group descriptor table: out of memory"));
    return FALSE;
  }
  memset((u8int*)group_desc_table, 0, sizeof(struct group_descriptor)*number_of_groups);
  data_block =(u8int*) kmalloc(dim_block);
  memset(data_block, 0, dim_block);

  if((err = ReadSectorsLba(0, (s32int)block_to_LBA(sbpos), spb, (u16int *)data_block, TRUE))){ /* IDE */
    monitor_write(("\n\rerror reading group descriptor block"));
    return FALSE;
  }
  memcpy((u8int*)group_desc_table, data_block, sizeof(struct group_descriptor)*number_of_groups);
  kfree(data_block);
  return TRUE;
}


struct group_descriptor * get_group_desc(u32int grp){
  if(grp>number_of_groups){
    monitor_write(("\n\rInvalid group descriptor number"));
    return NULL;
  }
  return(&group_desc_table[grp]);
}

/*void stampa_i(struct i_node *ino){
  int i;
  monitor_write(("\n\n\rtipo inode: %X",ino->i_mode & MODE_MASK);
  monitor_write(("\n\ruser id associato al file: %u",ino->i_uid);
  monitor_write(("\n\rfile size (byte): %u",ino->i_size);
  monitor_write(("\n\rnumero blocchi riservati al file: %u",ino->i_blocks);
  for (i=0;i<15;i++){
    monitor_write(("\n\rblock[%u]: %u",i,ino->i_block[i]);
  }
  kgetchar();
} */

/* */
u32int Inode2Block(u32int ino){
  struct group_descriptor* group_desc;
  if(!ino || ino>super->s_inodes_count){
    monitor_write(("\n\rinvalid inode number"));
    return 0;
  }
  ino--;
  if(!(group_desc = get_group_desc(ino/super->s_inodes_per_group))){
    monitor_write(("\n\rNot group desc per inode"));
    return 0;
  }
  ino %= super->s_inodes_per_group;
  return (group_desc->bg_inode_table+ino/ipb);
}


/* */
boolean ReadInode(u32int ino, struct i_node* data){
  u32int ino_block = Inode2Block(ino);
  if(!ino_block){
    monitor_write("\n\rerror finding inode block");
    return FALSE;
  }
  data_block =(u8int*)kmalloc(dim_block);
  memset(data_block, 0, dim_block);
  if((err = ReadSectorsLba(0, (s32int)block_to_LBA(ino_block), spb, (u16int *)data_block, TRUE))){
    monitor_write("\n\rerror reading inode block");
    return FALSE;
  }
  memcpy((u8int*)data, &data_block[((ino-1)%ipb)*sizeof(struct i_node)], sizeof(struct i_node));
  kfree(data_block);
  return TRUE;
}

/* inode table inicializacija */
boolean init_inode_table(){
  int i;
  dim_inode_table = super->s_inodes_count / 100;
  if(!(inode_table = (struct i_node_tab*)kmalloc(sizeof(struct i_node_tab)*dim_inode_table))){
    monitor_write("\n\rImpossible create inode table: out of memory");
    return FALSE;
  }
  memset((u8int*)inode_table, 0, sizeof(struct i_node_tab)*dim_inode_table);
  for (i = 0;i < dim_inode_table; i++){
    inode_table[i].i_node_n = 0;
    inode_table[i].ref = 0;
  }
  free_inode = dim_inode_table;
  return TRUE;
}

/* Least Resently Used */
int inode_LRU(){
  u16int lru = 0;
  int i;

  for(i = 1;  i<dim_inode_table; i++){
    if (inode_table[i].ref < inode_table[lru].ref){
      lru = i;
    }
  }
  return (lru);
}

/* Gauname inode */
struct i_node *get_inode(u32int i_node_number){
  int i;
  int pos_inode = -1;
  struct i_node new_inode;

  if(!i_node_number || i_node_number>super->s_inodes_count){
    monitor_write("\n\rInvalid inode number");
    return(NULL);
  }

  for(i=0; i < (dim_inode_table-free_inode); i++){
    if(inode_table[i].i_node_n == i_node_number){
      pos_inode = i; /* Įsimename inode pozicija */
      break;
    }
  }
  if(pos_inode == -1){
    ReadInode(i_node_number, &new_inode);
    if (free_inode>0){
      pos_inode = dim_inode_table - free_inode;
      free_inode--; 
    }
    else{
      pos_inode = inode_LRU();
    }
    inode_table[pos_inode].inode = new_inode;
    inode_table[pos_inode].i_node_n = i_node_number;
    inode_table[pos_inode].ref = 0;
  }
  for(i=0; i < (dim_inode_table-free_inode); i++){
    inode_table[i].ref = inode_table[i].ref >> 1;
    if(i == pos_inode){
      inode_table[i].ref = inode_table[i].ref | 0x8000;
    }
  }
  return (&inode_table[pos_inode].inode);
}


boolean isFile(struct i_node *ino){
  if((ino->i_mode & MODE_MASK)==MODE_FILE){
    return TRUE;
  }
  return FALSE;
}

/* Ar nuoroda? */
boolean isFastSymbolicLink(struct i_node *ino){
  if((ino->i_mode & MODE_MASK)==MODE_LINK){
    return TRUE;
  }
  return FALSE;
}

/* */
boolean ReadIndirect1(u32int *dst, u32int *cnt, u32int blk) {
  u32int * r1;
  int m;
  
  if(*cnt<=0){
    return TRUE;
  }

  r1 = (u32int *)kmalloc(dim_ptr * sizeof(u32int));
  memset((u8int*)r1, 0, dim_ptr * sizeof(u32int));

  if((err = ReadSectorsLba(0, (s32int)block_to_LBA(blk), spb, (u16int *)r1, TRUE))){ /* IDE*/
    monitor_write(("\n\rerror reading indirect addressing"));
    kfree(r1);
    return FALSE;
  }

  m = min(*cnt, dim_ptr);
  memcpy((u8int*)dst, (u8int*)r1, m<<2);
  kfree(r1);
  *cnt -= m;
  dst += m;
  return TRUE;
}
/* */
boolean ReadIndirect2(u32int *dst, u32int *cnt, u32int blk) {
  int i;
  u32int * r2;
  
  if(*cnt<=0){
    return TRUE;
  }
  
  r2 = (u32int *)kmalloc(dim_ptr * sizeof(u32int));
  
  if((err = ReadSectorsLba(0,(s32int)block_to_LBA(blk),spb,(u16int *)r2,TRUE))){ /* IDE */
    monitor_write(("\n\rerror reading second level indirect addressing"));
    kfree(r2);
    return FALSE;
  }

  for(i = 0; *cnt && i<dim_ptr; i++){
    if(!ReadIndirect1(dst, cnt, r2[i])){
      kfree(r2);
      return FALSE;
    }
  }
  kfree(r2);
  return TRUE;
}

/* Atidaryti failą ar directoriją ar nuorodą */
boolean Open_File(struct i_node* ino, u16int tipo_file){
  int i;
  char *fsl;
  u32int n, m;
  u32int *ptr;
  
  if(ino == NULL){
    monitor_write(("\n\rInvalid inode\n\r"));
    return FALSE;
  }

  if (!(tipo_file == MODE_DIR || tipo_file == MODE_FILE || tipo_file == MODE_LINK)){
    monitor_write(("\n\rInvalid file type\n\r"));
    return FALSE;
  }

  if((tipo_file==MODE_LINK) && (ino->i_size<64)){
    monitor_write("\n\rFast symbolic link path : ");

    fsl = (u8int *)kmalloc(sizeof(struct i_node));
    memset(fsl, 0, sizeof(struct i_node));
    memcpy((u8int*)fsl, (u8int*)ino, sizeof(struct i_node));
    for (i=39;i<(ino->i_size+39);i++){
      monitor_write_hex(fsl[i]);
    }
    monitor_write("\n\n\r");
    kfree(fsl);
    ptr_dir = (u32int *)kmalloc(0);
    return FALSE;
  }

  n = (ino->i_size+dim_block-1)/dim_block;
  ptr_dir = (u32int *)kmalloc(n * sizeof(u32int));
  memset((u8int*)ptr_dir,0,n * sizeof(u32int));
  ptr = (u32int *)ptr_dir;
  m = (n<12) ? n : 12;
  
  if(m){
    memcpy((u8int*)ptr,(u8int*)ino->i_block,m<<2);
  }
  n-=m;
  ptr += m;

  if(!ReadIndirect1(ptr, &n, ino->i_block[12])){
    kfree(ptr_dir);
    return FALSE;
  }
  if(!ReadIndirect2(ptr,&n,ino->i_block[13])){
    kfree(ptr_dir);
    return FALSE;
  }
  if(n){
    u32int *r3 = (u32int *)kmalloc(dim_ptr * sizeof(u32int));
    if((err = ReadSectorsLba(0, block_to_LBA(ino->i_block[14]), spb, (u16int *)r3, TRUE))){ /* IDE */
      monitor_write("\n\rerror reading third level indirect addressing");
      kfree(r3);
      return FALSE;
    }

    for(i = 0; n && i<dim_ptr; i++){
      if(!ReadIndirect2(ptr, &n, r3[i])){
        kfree(ptr_dir);
        kfree(r3);
        return FALSE;
      }
    }
    kfree(r3);
  }
  return TRUE;
}


/* Ar tikrai directorija? */
boolean isDir(struct i_node *ino){
  if((ino->i_mode & MODE_MASK)==MODE_DIR){
    return TRUE;
  }
  return FALSE;
}


u32int FindFile(char *cmp){
  int i;

  for(i=0; i<count_dir; i++){
    if(!strcmp(cmp, ext2_file_name[i])){
      return inode_dir[i];
    }
  }
  return 0;
}


/* Atidarome directorija */
boolean Open_Dir(struct i_node* inode){
  u8int *ptr_block;
  u32int block_dir;
  u8int *tmp;
  int i, len, idx;
  struct dir_ff *dir;

  if(!(isDir(inode) || isFastSymbolicLink(inode))){
    return FALSE;
  }
  if(ext2_file_name != 0){
    kfree(inode_dir);
    kfree(file_type_dir);
    kfree(text);
    kfree(ext2_file_name);
  }
  
  if(!(Open_File(inode, inode->i_mode & MODE_MASK))){
    return FALSE;
  }
  block_dir = (inode->i_size + dim_block - 1)/dim_block;
  tmp = (u8int *)kmalloc(inode->i_size);
  memset(tmp, 0, inode->i_size);
  ptr_block = (u8int *)tmp;
  for (i = 0; i<block_dir; i++){
    if((err = ReadSectorsLba(0, (s32int)block_to_LBA(ptr_dir[i]), spb, (u16int *)ptr_block, TRUE))){ /* IDE */
      monitor_write("\n\rError reading data block");
      kfree(ptr_dir);
      kfree(tmp);
      return FALSE;
    }
    ptr_block += dim_block;
  }
  kfree(ptr_dir);
  
  count_dir = 0; 
  len = 0;
  for(i = 0; i<inode->i_size; ){
    dir = (struct dir_ff*)&tmp[i];
    if(dir->inode){
      count_dir++;
      len += dir->name_len + 1;
    }
    i += dir->rec_len;
  }
  
  inode_dir = (u32int *)kmalloc(count_dir * sizeof(u32int));
  memset((u8int*)inode_dir,0,count_dir * sizeof(u32int));
  file_type_dir = (u8int *)kmalloc(count_dir);
  memset(file_type_dir, 0, count_dir);
  ext2_file_name =(char **) kmalloc(count_dir*sizeof(char *));
  text = (char *)kmalloc(len);
  memset(text, 0, len);

  idx = 0;
  for (len = i = 0;i<inode->i_size;){
    dir = (struct dir_ff*)&tmp[i];
    if (dir->inode){
      inode_dir[idx] = dir->inode;
      file_type_dir[idx] = dir->file_type;
      memcpy(&text[len],dir->name,dir->name_len);
      text[len+dir->name_len] = '\0';
      ext2_file_name[idx++] = &text[len];
      len += dir->name_len + 1;
    }
    i += dir->rec_len;
  }
  kfree(tmp);
  return TRUE;
}


struct time_ext2 det_time(u32int ino_time){
  struct time_ext2 t;
  u32int s;

  s = ino_time % 86400;
  t.hour = s / 3600;
  s -= t.hour*3600;
  t.min = (s / 60);
  s -= t.min*60;
  t.seconds = s;
  return(t);
}

struct date_ext2 det_date(u32int ino_time){
  struct date_ext2 d;
  u32int mg;

  ino_time = ino_time / 86400; /*(60*60*24)*/

  mg = ino_time + 1;
  for(d.year=1970;;d.year++){
    if((d.year % 4)==0){
      if(mg<366){
        break;
      }
      mg -= 366;
    }
    else{
      if(mg<365){
        break;
      }
      mg -= 365;
    }
  }

  for(d.month=1;;d.month++){
    if((d.month==4)||(d.month==6)||(d.month==9)||(d.month==11)){
      if(mg<=30){
        break;
      }
      mg -= 30;
    }
    else if((d.month==2)&&(d.year%4==0)){
      if(mg<=29){
        break;
      }
      mg -= 29;
    }
    else if((d.month==2)&&(d.year%4!=0)){
      if(mg<=28){
        break;
      }
      mg -= 28;
    }
    else{
      if(mg<=31){
        break;
      }
      mg -= 31;
    }
  }
  d.day = mg;
  return(d);
}

char *pwd_ext2(){
  if(mount_ext2){
    return(path_ext2);
  }
  else{
    return('\0');
  }
}


void ls_ext2(){
  int i;
  struct i_node* info_file;
  if(mount_ext2){
    for(i=0; i<count_dir; i++){
      info_file = get_inode(inode_dir[i]);
      tempo = det_time(info_file->i_ctime);
      data = det_date(info_file->i_ctime);
      if((info_file->i_mode&MODE_MASK)==MODE_LINK){
        continue;
      }
      
      /*  KA DARYT ?Ą?Ą */
      switch(info_file->i_mode & MODE_MASK){
        case MODE_FILE:
          monitor_color(WHITE);
        break;

        case MODE_DIR:
          monitor_color(LIGHT_BLUE);
        break;

        case MODE_CDEV:
          monitor_color(LIGHT_GREEN);
        break;

        case MODE_BDEV:
          monitor_color(LIGHT_RED);
        break;

        case MODE_FIFO:
          monitor_color(LIGHT_MAGENTA);
        break;

        case MODE_SOCK:
          monitor_color(LIGHT_CYAN);
        break;

        case MODE_LINK:
          monitor_color(RED);
        break;
      }

      monitor_write("\n ");
      monitor_write(ext2_file_name[i]);
      monitor_write("  ");
      monitor_color(DEFAULT_COLOR);
      monitor_write("Size: ");
      monitor_write_dec(info_file->i_size);
      monitor_write("  ");
      monitor_write_dec(data.year);
      monitor_write(":");
      monitor_write_dec(data.month);
      monitor_write(":");
      monitor_write_dec(data.day);
      if(((i+1)%22)==0){
        monitor_write("\n\r ------ Continue ------");
        if(getchar()==CTRL_C){
          monitor_write("\n\n\r");
          return;
        }
        monitor_clear();
      }
    }
  }
  else{
    monitor_write("\n\rUnmounted File System Ext2\n\r");
  }
  return;
}


void cd_ext2(char *param){
  struct i_node* ino;
  int i, j_param, len_param, i_param;
  u32int ino_dir;
  char elem_path[256];
  boolean errore;

  if(!mount_ext2){
    monitor_write("\n\rUnmounted File System Ext2\n\r");
    return;
  }

  if(!strcmp(param,".")){
    return;
  }
  if(!strcmp(param,"/")){
    if(!Open_Dir(get_inode(EXT2_ROOT_INO))){
      mount_ext2 = FALSE;
      return;
    }
    level = 0;
    path_ext2[0]='\0';
    return;
  }

  if((level == 0)&&!strcmp(param,"..")){
    monitor_write("\n\rThis is root.\n\r");
  }
  else if((level ==1)&&!strcmp(param,"..")){
    if (!Open_Dir(get_inode(EXT2_ROOT_INO))){
      mount_ext2 = FALSE;
      return;
    }
    level = 0;
    path_ext2[0]='\0';
    ino_current_dir = EXT2_ROOT_INO;
  }
  else{
    errore = FALSE;
    memcpy((u8int*)&path_ext2_backup, (u8int*)&path_ext2, 1024);
    level_backup = level;
    ino_dir_backup = ino_current_dir;
    i_param = 0;
    if(param[0]=='.'&&param[1]=='/'){
      i_param = 2;
    }
    if(param[strlen(param)-1]=='/'){
      len_param = strlen(param)-1;
    }
    else{ 
      len_param = strlen(param);
    }

    for(j_param=0;i_param<=len_param;i_param++){
      if((param[i_param]=='/')||(i_param==len_param)){
        elem_path[j_param]='\0';
        j_param = 0;
        if(!(ino_dir=FindFile(elem_path))){
          monitor_write("\n\rDirectory no match\n\r");
          errore = TRUE;
          break;
        }
        else if(!(ino=get_inode(ino_dir))){
          errore = TRUE;
          break;
        }
        else if(!(isDir(ino)||isFastSymbolicLink(ino))){
          monitor_write("\n\rNot a directory\n\r");
          errore = TRUE;
          break;
        }
        else if(!Open_Dir(ino)){
          if(!isFastSymbolicLink(ino)){
            monitor_write("\n\rOpen failed\n\r");
          }
          errore = TRUE;
          break;
        }
        else{
          if(!strcmp(elem_path, "..")){
            if(level){
              level--;
              for(i=strlen(path_ext2)-2; path_ext2[i]!='/'; i--);
              path_ext2[i+1]='\0';
            }
            if(!level){
              path_ext2[0]='\0';
            }
          }
          else{
            strcat(path_ext2, elem_path);
            strcat(path_ext2, "/");
            level++;
          }
          ino_current_dir = ino_dir;
        }
      }
      else{
        elem_path[j_param++] = param[i_param];
      }
      if(errore){
        monitor_write("\n\rErorr\n\r");
        level = level_backup;
        memcpy((u8int*)&path_ext2,(u8int*)&path_ext2_backup, 1024);
        ino_current_dir = ino_dir_backup;
        Open_Dir(get_inode(ino_current_dir));
      }
    }
  }
}

void cat_ext2(char *param){
  struct i_node * ino;
  u32int i;
  u16int block_file;
  char *c=NULL;
  int stop=0, ll=0;
  u32int ino_file;

  if(!mount_ext2){
    monitor_write("\n\rUnmounted File System Ext2\n\r");
    return;
  }

  if(!(ino_file = FindFile(param))){
    monitor_write("\n\rNo such file\n\r");
    return;
  }
  else if(!(ino=get_inode(ino_file))){
    monitor_write("\n\rERROR:Bad inode number\n\r");
  }
  else if(!(isFile(ino)||isFastSymbolicLink(ino))){
    monitor_write("\n\rNot a regular file\n\r");
    return;
  }
  else if(Open_File(ino,ino->i_mode & MODE_MASK)){
    block_file = 0;
    stop = 3;
    data_block = (u8int *)kmalloc(dim_block);
    memset(data_block, 0, dim_block);
    monitor_color(LIGHT_BLUE);
    monitor_write("filename: %s\n\n\r");
    monitor_write(param);
    monitor_color(DEFAULT_COLOR);
    for(i=0;i<ino->i_size;i++){
      if(i % dim_block ==0){
        if((err = ReadSectorsLba(0, (s32int)block_to_LBA(ptr_dir[block_file]), spb, (u16int *)data_block, TRUE))){ /* IDE */
          monitor_write(("\n\rError reading file data block"));
          kfree(ptr_dir);
          kfree(data_block);
          return;
        }
        block_file++;
        c = (char *)data_block;
      }
      if(*c==10){
        stop++;
        monitor_write("\n\r");
        ll=0;
      }
      else{
        monitor_put(*c);
        if(ll++>70){
          stop++;
          ll = 0;
        }
      }
      c++;
      if(((stop)%22)==0){
        monitor_write(("\n\r ------ Continue ------"));
        if(getchar()==CTRL_C){
          kfree(data_block);
          monitor_write("\n\r");
          return;
        }
        monitor_clear();
        stop = 3;
        monitor_color(LIGHT_BLUE);
        monitor_write("filename: ");
        monitor_write(param);
        monitor_write("\n\n\r");
        monitor_color(DEFAULT_COLOR);
      }
    }
    kfree(data_block);
  }
}

/* Patikriname ar įrenginyje yra ext2 */
boolean read_ext2(){
  int dev, sec;
  data_block = (u8int *) kmalloc(DIM_SUPER_BLOCK);
  memset((u8int *)data_block, 0, DIM_SUPER_BLOCK);
  dev = 0;
  sec = 2;
  SelectAtaChannel(CC_PRIMARY); /* IDE , ATA */

  if((err = ReadSectorsLba(dev, (s32int)block_to_LBA(0)+sec, 2,(u16int *)data_block, TRUE))){ /* ReadSectorsLba IDE funkcija */
    monitor_write("\nError Reading block");
    return FALSE;
  }
  else{
    super =(struct super_block *) kmalloc(sizeof(struct super_block));
    memcpy((u8int *)super,(u8int *)data_block, sizeof(struct super_block));
    return TRUE;
  }
  kfree(data_block);
}

/* Ar ext2 tvarkingas */
boolean check_ext2(){
  if((super->s_magic != N_EXT2_NUMERO_MAGICO)&&(super->s_magic != P_EXT2_NUMERO_MAGICO)){
    monitor_write("\n\rNot a valid ext2.\n\r");
    return(FALSE);
  }
  else{
    return TRUE;
  }
}

/* Inicijuojame ext2 */
boolean init_ext2(){

  ext2_file_name=NULL; /* Failo pavadinimas */
  inode_dir=0; /* inodes */
  file_type_dir=0; /* Failo tipas */
  text=0;
  name=0;
  
  path_ext2[0] = '\0'; /* Inicijuojame kelią */
  if(!read_ext2()){
    return(FALSE);
  }
  if(!check_ext2()){
    return(FALSE);
  }
  dim_block = 1024 << super->s_log_block_size;
  dim_frag = 1024 << super->s_log_frag_size;
  spb = dim_block / SIZE_SEC; /* Sectorių blokui */
  sbpos = super->s_first_data_block + 1; /* Super bloko pozicija */
  bpg = super->s_blocks_per_group; /* Blokų grupėje */
  gdpb = dim_block / sizeof(struct group_descriptor); /* grupių descriptorių bloke */
  ipb = dim_block / super->s_inode_size; /* inode'ų bloke */
  number_of_groups = super->s_inodes_count / super->s_inodes_per_group; /* Grupių skaičius */
  dir_entries_per_block = dim_block / sizeof(struct dir_ff); /* Direktorijų bloke */
  dim_ptr = dim_block >> 2;

  /* Inicijuojame Group Descriptor table */
  if(!init_group_desc_table()){
    return(FALSE);
  }
  /* Inicijuojame inode table */
  if(!init_inode_table()){
    return(FALSE);
  }
  if (!Open_Dir(get_inode(EXT2_ROOT_INO))){
    return(FALSE);
  }
  ino_current_dir = EXT2_ROOT_INO;
  mount_ext2 = TRUE;
  level = 0;
  return(TRUE);
}

void ext2(){
  monitor_write("\n\rExt2 parameters\n\r");
  monitor_write("\n\rTotal number of inodes:                         ");
  monitor_write_dec(super->s_inodes_count);
  monitor_write("\n\rTotal number of block:                          ");
  monitor_write_dec(super->s_blocks_count);
  monitor_write("\n\rNumber of blocks reserved for the super user:   ");
  monitor_write_dec(super->s_r_blocks_count);
  monitor_write("\n\rNumber of groups:                               ");
  monitor_write_dec(number_of_groups);
  monitor_write("\n\rBlock per group:                                ");
  monitor_write_dec(bpg);
  monitor_write("\n\rBlock dimension:                                ");
  monitor_write_hex(dim_block);
  monitor_write("\n\rFragment dimension:                             ");
  monitor_write_hex(dim_frag);
  monitor_write("\n\rSector per block:                               ");
  monitor_write_dec(spb);
  monitor_write("\n\rDirectories per block:                          ");
  monitor_write_dec(dir_entries_per_block);
  monitor_write("\n\rGroup descriptors per block:                    ");
  monitor_write_dec(gdpb);
  monitor_write("\n\rInodes per group:                               ");
  monitor_write_dec(super->s_inodes_per_group);
  monitor_write("\n\rFrags per group:                                ");
  monitor_write_dec(super->s_frags_per_group);
  monitor_write("\n\rInodes per block:                               ");
  monitor_write_dec(ipb);
  monitor_write("\n\r");
}
